package xyz.thoughtset.viewer.modules.api.controller;


import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.HandlerMapping;
import xyz.thoughtset.viewer.common.api.controller.BaseController;
import xyz.thoughtset.viewer.executor.blocks.executor.BlockExecutorManager;
import xyz.thoughtset.viewer.modules.api.constants.ApiParamTypeConstant;
import xyz.thoughtset.viewer.modules.api.entity.ApiInfo;
import xyz.thoughtset.viewer.modules.api.entity.ApiParam;
import xyz.thoughtset.viewer.modules.api.service.ApiInfoService;
import xyz.thoughtset.viewer.modules.datarel.constants.RelTopicConstant;
import xyz.thoughtset.viewer.modules.datarel.entity.DataRel;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
//@ResponseBody
@SuppressWarnings({"unchecked","SpringJavaInjectionPointsAutowiringInspection"})
public class RequestController extends BaseController {
    @Autowired
    protected BlockExecutorManager blockExecutorManager;
//    @Autowired
//    protected ApiInfoService apiInfoService;

    @Setter
    String key;
    @Setter
    String beanName;

    ApiInfo apiInfo;

    public void setApiInfo(ApiInfo apiInfo) {
        this.apiInfo = apiInfo;
        if (apiInfo != null && !ObjectUtils.isEmpty(apiInfo.getId())) {
            key = apiInfo.getId();
        }
    }



    @RequestMapping
    @ResponseBody
    public Object invoke(HttpServletRequest request, HttpServletResponse response,
                         @RequestBody(required = false) Map<String, Object> requestBody,
//                         @PathVariable(required = false) Map<String, Object> pathVariables,
                         @RequestHeader(required = false) Map<String, Object> defaultHeaders,
                         @RequestParam(required = false) Map<String, Object> parameters){
        System.out.println(request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE));
        Map dataMap;
        dataMap = switch (apiInfo.getQueryType()){
            case 12 -> requestBody;
            case 11 -> parameters;
            default -> new HashMap<>();
        };
        if (dataMap == null) dataMap = new HashMap<>();
        List<ApiParam> apiParams = apiInfo.getApiParams();
        for (ApiParam param:apiParams){
            int typeNum = param.getParamType();
            if (ApiParamTypeConstant.RequestParam == typeNum){
                filterParam(param,parameters,dataMap);
            } else if (ApiParamTypeConstant.RequestBody == typeNum){
                filterParam(param,requestBody,dataMap);
            } else if (ApiParamTypeConstant.INNER == typeNum){
                String key = param.getTitle();
                Object paramValue = param.getDefaultVal();
                dataMap.put(key, paramValue);
            }
        }
        SpelExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariables(dataMap);
        String execKey = chooseExecKey(parser,context);
        if (!StringUtils.hasText(execKey)) return null;
        return blockExecutorManager.execBlocks(execKey,dataMap,parser,context);
    }

    protected void filterParam(ApiParam param,Map inMap,Map map){
        String key = param.getTitle();
        Object paramValue = inMap.get(key);
        if (paramValue == null) {
            paramValue = param.getDefaultVal();
        }
        map.put(key, paramValue);
    }

    protected String chooseExecKey(SpelExpressionParser parser,StandardEvaluationContext context){
        List<DataRel> funRels = apiInfo.groupRels().get(RelTopicConstant.FUN_INFO);
        for (DataRel rel : funRels){
            String exp = rel.getDataExp();
            if (!StringUtils.hasText(exp)) return rel.getTarget();
            if (checkCondition(exp, parser, context)) return rel.getTarget();
        }
        return null;
    }

    private boolean checkCondition(String exp, SpelExpressionParser parser, StandardEvaluationContext context) {
        Object result = parser.parseExpression(exp.startsWith("#")?exp:"#"+exp).getValue(context);
        if (result instanceof Boolean) {
            return result != null && ((Boolean) result).booleanValue();
        }
        return !ObjectUtils.isEmpty(result);
    }

}
